﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;

namespace SuperKit
{

    public struct ImageSameInfo {
        public float same;
        public ImageGroupItem item;

        public bool Enable => item != null;

        public ImageSameInfo(float same, ImageGroupItem item) {
            this.same = same;
            this.item = item;
        }
    }

    public class ImageGroupItem {
        public const int DEFAULT_COLOR_DIFF = 8;

        public FileInfo Info { get; }
        private Size Size { get; }
        private int Width => Size.Width;
        private int Height => Size.Height;
        private byte[] data;
        public List<ImageSameInfo> SameItems { get; set; }
        /// <summary>在这一个组之间，有多少个图片和这个图片相似</summary>
        public int SameCount { get; set; }
        /// <summary>是否还有效</summary>
        public bool Enable { get; set; }

        public ImageGroupItem(FileInfo info, Size size) {
            this.Info = info;
            this.Size = size;
            CreateCompareData();
            Enable = true;
        }

        unsafe private void CreateCompareData() {
            Image img = null;
            try {
                img = Image.FromFile(Info.FullName);
            }catch (IOException) {
                // 如果出现IO错误，可能是因为对方的文件有问题，设置一个假的项目
                data = new byte[Width * Height];
                return;
            }
            
            Bitmap bmp = new Bitmap(img, Size);

            Rectangle rect = new Rectangle(0, 0, Width, Height);
            var tmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            int count = Width * Height;
            int dataSize = count * 3; // Format24bppRgb使用3个字节
            byte* p1 = (byte*)tmpData.Scan0;
            data = new byte[dataSize];
            for (int i = 0; i < dataSize; i++) {
                data[i] = p1[i];
            }

            bmp.UnlockBits(tmpData);
            bmp.Dispose();
            img.Dispose();
        }

        public void Compare(List<ImageGroupItem> bitmaps, float same, int colorDiff) {
            SameItems = new List<ImageSameInfo>();
            foreach (var i in bitmaps) {

                // 跳过自己 
                if (string.Equals(i.Info.FullName, Info.FullName, StringComparison.OrdinalIgnoreCase)) {
                    continue;
                }

                var rate = GetCompare(i);
                if (rate > same) {
                    SameItems.Add(new ImageSameInfo(rate, i));
                    i.SameCount++;
                }
            }
        }

        /// <summary>
        /// 比较两个项目，返回相似率
        /// </summary>
        /// <param name="obj">比较的目标对象</param>
        /// <param name="colorDiff">色差范围，在色差的多少范围之中算相似。</param>
        /// <returns>相似率，0-1范围之间的值</returns>
        unsafe private float GetCompare(ImageGroupItem obj, int colorDiff = DEFAULT_COLOR_DIFF) {
            // 得到总数值项
            float same = 0;

            for (int i = 0; i < data.Length; i++) {
                if (Math.Abs(data[i] - obj.data[i]) < colorDiff) {
                    same++;
                }
            }

            return (same / (float)data.Length);
        }

        public void Release() {
            data = null;
        }
    }


    public class ImageGroup {
        public ImageCompare Parent { get; }
        public FileGroup Group { get; }
        public List<FileInfo> Files { get; set; }
        public List<ImageGroupItem> Items { get; set; }
        public int MaxSize { get; }
        public Size Size { get; }
        public const int DEFAULT_PIXEL = 100;

        public int Count => Files.Count;
        public bool IsEmpty => Files.Count == 0;
        public string Name => Group.Dir.Name;
        public int KeepCount => Parent.GetKeepCount(this);

        public ThreadStatus Status { get; set; }

        public ImageGroup(ImageCompare parent, FileGroup group, int maxSize = DEFAULT_PIXEL) {
            Parent = parent;
            Group = group;
            Files = new List<FileInfo>();
            MaxSize = maxSize;
            Size = new Size(maxSize, maxSize);
            Status = ThreadStatus.READY;

            if (group.Files != null) {
                foreach (var i in group.Files) {
                    if (Kit.IsFileType(i, Kit.PROCESSED_IMG_EXTS)) {
                        Files.Add(i);
                    }
                }
            }

        }

        public float SaveMB { get; private set; }
        public float DelMB { get; private set; }
        public float TotalMB => SaveMB + DelMB;
        public int SaveCount { get; private set; }
        public int DelCount { get; private set; }

        public void CalculateCount() {
            SaveMB = 0f;
            DelMB = 0f;
            SaveCount = 0;
            DelCount = 0;

            foreach (var i in Items) {
                if (i.Enable) {
                    SaveMB += i.Info.Length / (float)Kit.MB;
                    SaveCount++;
                    // Flush("保留：{0}(相似:{1})", i.Info.Name, i.SameCount);
                } else {
                    DelMB += i.Info.Length / (float)Kit.MB;
                    DelCount++;
                }
            }
        }

        public void CreateBitmaps() {
            Items = new List<ImageGroupItem>(Count);
            foreach (var i in Files) {
                Items.Add(new ImageGroupItem(i, Size));
                Parent.SetStatus("Load:{0}", i.FullName);
            }
        }

        public void Compare(float same, int colorDiff) {            
            foreach (var bmp in Items) {
                bmp.Compare(Items, same, colorDiff);
            }

        }
        public int GetEnableCount() {
            int count = 0;
            foreach (var i in Items) {
                if (i.Enable) {
                    count++;
                }
            }
            return count;
        }

        public void Cut(int keep) {
            // 从相似度最高的开始减起
            while (GetEnableCount() > keep) {
                var hasSame = CutTop();
                if (hasSame == false) {
                    Parent.Flush("{0}中断因为没有更相似内容，剩余：{1}个", Name, GetEnableCount());
                    break;
                }
            }
        }

        private bool CutTop() {
            ImageSameInfo item = new ImageSameInfo(0f, null);

            foreach (var i in Items) {
                if (i.Enable == false) {
                    continue;
                }

                foreach (var b in i.SameItems) {
                    if (b.item.Enable == false) {
                        continue;
                    }
                    if (!item.Enable || item.same < b.same) {
                        item = b;
                    }
                }

            }
            if (item.Enable) {
                item.item.Enable = false;
                return true;
            } else {
                return false;
            }
        }

        public void Start() {
            Status = ThreadStatus.PROCESS;
            Thread t = new Thread(StartCompare);
            t.Start();
        }

        private void StartCompare() {
            CreateBitmaps();
            Compare(Parent.SameRate, Parent.ColorDiff);
            Cut(KeepCount);
            Parent.Print(this);
            Parent.Move(this);
            Status = ThreadStatus.COMPLETE;
            Release();
        }

        private void Release() {
            foreach (var i in Items) {
                i.Release();
            }
        }
    }
}
